﻿using UnityEngine;
using System.Collections;
using Space2D_Core;
using Space2D_Utils;
using System.Collections.Generic;

public class Main : MonoBehaviour
{
	private void Start ()
	{
		Logger.EventLog += OnLog;

		WorldManager.EventRegistered += OnObjectRegistered;
		WorldManager.EventDeRegistered += OnObjectDeRegistered;
		WorldManager.Init(6.67545E-11, 1.0E+6, new Vector2d(10000000000, 10000000000));


		PhysicalObject sun = new PhysicalObject("sun", 1.99E+27);
		sun.Init(new Vector2d(0, 0), new Vector2d(0, 0), new Vector2d(0, 0));
		/*PhysicalObject sun1 = new PhysicalObject("sun", 1.99E+27);
		sun1.Init(new Vector2d(0, 0), new Vector2d(0, 10000), new Vector2d(5000000, 0));

		PhysicalObject sun2 = new PhysicalObject("sun", 1.99E+27);
		sun2.Init(new Vector2d(0, 0), new Vector2d(-8660, -5000), new Vector2d(-2500000, 4330000));

		PhysicalObject sun3 = new PhysicalObject("sun", 1.99E+27);
		sun3.Init(new Vector2d(0, 0), new Vector2d(8660, -5000), new Vector2d(-2500000, -4330000));*/
		
		PhysicalObject earth = new PhysicalObject("earth", 5.972E+21);
		earth.Init(new Vector2d(0, 0), new Vector2d(0, 30000), new Vector2d(150000000, 0));

		PhysicalObject moon = new PhysicalObject("moon", 7.36E+16);
		moon.Init(new Vector2d(0, 0), new Vector2d(0, 31000), new Vector2d(150384000, 0));

		PhysicalObject jupiter = new PhysicalObject("jupiter", 1.8986E+21);
		jupiter.Init(new Vector2d(0, 0), new Vector2d(0, 15070), new Vector2d(778547200, 0));

		PhysicalObject saturn = new PhysicalObject("saturn", 5.6846E+23);
		saturn.Init(new Vector2d(0, 0), new Vector2d(0, 13500), new Vector2d(1433449400, 0));

		PhysicalObject uranus = new PhysicalObject("uranus", 8.6832E+22);
		uranus.Init(new Vector2d(0, 0), new Vector2d(0, 9000), new Vector2d(2876679100, 0));

		PhysicalObject neptun = new PhysicalObject("neptun", 1.0243E+23);
		neptun.Init(new Vector2d(0, 0), new Vector2d(0, 7500), new Vector2d(4503443700, 0));

		PhysicalObject ship = new Ship("ship", 10000, 3000, 3E+7, 1.5E+14);
		ship.Init(new Vector2d(0, 0), new Vector2d(0, 32500), new Vector2d(150065000, 0));

		/*WorldManager.Register(sun1);
		WorldManager.Register(sun2);
		WorldManager.Register(sun3);*/

		m_cur = ship;
		m_cameraOffset = m_cur.Position;
		WorldManager.Register(ship);

		WorldManager.Register(sun);
		WorldManager.Register(earth);
		WorldManager.Register(moon);
		WorldManager.Register(jupiter);
		WorldManager.Register(saturn);
		WorldManager.Register(uranus);
		WorldManager.Register(neptun);


		for (int i = 0; i < 30; ++i)
		{
			PhysicalObject asteroid1 = new PhysicalObject("asteroid_1", 100000);
			asteroid1.Init(new Vector2d(0, 0), new Vector2d(0, 32500),
				new Vector2d(Random.Range(150060000, 150070000), Random.Range(-10000, 10000)));

			PhysicalObject asteroid2 = new PhysicalObject("asteroid_2", 100000);
			asteroid2.Init(new Vector2d(0, 0), new Vector2d(0, 32500),
				new Vector2d(Random.Range(150060000, 150070000), Random.Range(-10000, 10000)));

			PhysicalObject asteroid3 = new PhysicalObject("asteroid_3", 100000);
			asteroid3.Init(new Vector2d(0, 0), new Vector2d(0, 32500),
				new Vector2d(Random.Range(150060000, 150070000), Random.Range(-10000, 10000)));

			PhysicalObject asteroid4 = new PhysicalObject("asteroid_4", 100000);
			asteroid4.Init(new Vector2d(0, 0), new Vector2d(0, 32500),
				new Vector2d(Random.Range(150060000, 150070000), Random.Range(-10000, 10000)));

			WorldManager.Register(asteroid1);
			WorldManager.Register(asteroid2);
			WorldManager.Register(asteroid3);
			WorldManager.Register(asteroid4);
		}

		float zoom = (float)System.Math.Pow(10, m_curZoom);
		Camera.main.orthographicSize = zoom;
		Camera.main.transform.position = new Vector3((float)(m_cur.Position.X - m_cameraOffset.X),
			(float)(m_cur.Position.Y - m_cameraOffset.Y), Camera.main.transform.position.z);
	}

	private void Update()
	{
		Ship ship = m_cur as Ship;

		/*if (Input.GetMouseButtonUp(0))
		{
			ship.SetEnginePower(ship.EngineDirection, 0.0);
		}

		if (Input.GetMouseButtonDown(0) || Input.GetMouseButton(0))
		{
			Vector3 camPos = Camera.main.transform.position;
			Camera.main.transform.position = Vector3.zero;
			Vector3 deltaTouchWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
			Camera.main.transform.position = camPos;

			Vector2d deltaTouch = new Vector2d(deltaTouchWorldPos.x, deltaTouchWorldPos.y);
			ship.SetEnginePower(deltaTouch.Normalized(), 1.0);
		}*/

		if (Input.GetMouseButton(0))
		{
			Vector3 camPos = Camera.main.transform.position;
			Camera.main.transform.position = Vector3.zero;
			Vector3 deltaTouchWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
			Camera.main.transform.position = camPos;

			Vector2d deltaTouch = new Vector2d(deltaTouchWorldPos.x, deltaTouchWorldPos.y);

			PhysicalObject bullet = new PhysicalObject("bullet", 1);
			bullet.Init(new Vector2d(0, 0), ship.Speed + new Vector2d(deltaTouch, 2000), ship.Position + new Vector2d(deltaTouch, 1));
			WorldManager.Register(bullet);
		}

		Vector2d dir = new Vector2d(0, 0);

		if (Input.GetKey(KeyCode.W))
		{
			dir += new Vector2d(0, 1);
		}

		if (Input.GetKey(KeyCode.S))
		{
			dir += new Vector2d(0, -1);
		}

		if (Input.GetKey(KeyCode.A))
		{
			dir += new Vector2d(-1, 0);
		}

		if (Input.GetKey(KeyCode.D))
		{
			dir += new Vector2d(1, 0);
		}

		if (dir.SqrLength > 0.0)
		{
			ship.SetEnginePower(dir.Normalized(), 1.0);
		}
		else
		{
			ship.SetEnginePower(dir.Normalized(), 0.0);
		}

		float curZoom = m_curZoom;
		curZoom += m_zoomStepScale * Input.GetAxis("Mouse ScrollWheel");
		if (curZoom < m_minZoom)
		{
			curZoom = m_minZoom;
		}

		if (m_curZoom != curZoom)
		{
			m_curZoom = curZoom;
			float zoom = (float)System.Math.Pow(10, m_curZoom);
			Camera.main.orthographicSize = zoom;
		}

		/*for (int i = 0; i < 100; ++i)
		{
			WorldManager.Tick(100);
		}*/

		WorldManager.Tick((int)(Time.deltaTime * 1000));

		Camera.main.transform.position = new Vector3((float)(m_cur.Position.X - m_cameraOffset.X),
			(float)(m_cur.Position.Y - m_cameraOffset.Y), Camera.main.transform.position.z);

		if (Input.GetMouseButton(1))
		{
			Vector3 camPos = Camera.main.transform.position;
			Camera.main.transform.position = Vector3.zero;
			Vector3 deltaTouchWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
			Camera.main.transform.position = camPos;

			Camera.main.transform.position = Camera.main.transform.position + new Vector3(deltaTouchWorldPos.x, deltaTouchWorldPos.y, 0.0f);
		}
	}

	private void OnGUI()
	{
		GUI.Label(new Rect(20, 20, 300, 20), "Speed: " + m_cur.Speed.SqrtLength.ToString());
		GUI.Label(new Rect(20, 40, 300, 20), "Acceleration: " + m_cur.GetTotalAcceleration().SqrtLength.ToString());
		GUI.Label(new Rect(20, 60, 300, 20), "Objects in world: " + m_renderers.Count.ToString());
		GUI.Label(new Rect(20, 80, 300, 20), "FPS: " + 1.0f / Time.deltaTime);

		LineRender.Draw(Color.green, new Vector3((float)(m_cur.Position.X - m_cameraOffset.X),
			(float)(m_cur.Position.Y - m_cameraOffset.Y), 0),
			new Vector3((float)(m_cur.Position.X - m_cameraOffset.X + m_cur.Speed.X),
				(float)(m_cur.Position.Y - m_cameraOffset.Y + m_cur.Speed.Y), 0));

		LineRender.Draw(Color.yellow, new Vector3((float)(m_cur.Position.X - m_cameraOffset.X),
			(float)(m_cur.Position.Y - m_cameraOffset.Y), 0),
			new Vector3((float)(m_cur.Position.X - m_cameraOffset.X + m_cur.GetTotalAcceleration().X),
				(float)(m_cur.Position.Y - m_cameraOffset.Y + m_cur.GetTotalAcceleration().Y), 0));
	}

	private void OnObjectRegistered(PhysicalObject obj)
	{
		GameObject gameObj = Utils.LoadPrefab(obj.Name);
		obj.EventPosChanged += ObjectPosChanged;
		gameObj.transform.position = new Vector3((float)(obj.Position.X - m_cameraOffset.X),
			(float)(obj.Position.Y - m_cameraOffset.Y), gameObj.transform.position.z);

		if (obj.Name.Contains("asteroid_"))
		{
			gameObj.transform.rotation = Quaternion.Euler(0, 0, Random.Range(0, 180));
		}

		PhysicalObjectRenderer renderer = gameObj.GetComponent<PhysicalObjectRenderer>();
		renderer.Init(obj);
		m_renderers.Add(obj, gameObj);
	}

	private void OnObjectDeRegistered(PhysicalObject obj)
	{
		obj.EventPosChanged -= ObjectPosChanged;

		Destroy(m_renderers[obj]);

		m_renderers.Remove(obj);
	}

	private void ObjectPosChanged(PhysicalObject obj)
	{
		GameObject gameObj = m_renderers[obj];

		gameObj.transform.position = new Vector3((float)(obj.Position.X - m_cameraOffset.X),
			(float)(obj.Position.Y - m_cameraOffset.Y), gameObj.transform.position.z);
	}

	private void OnLog(string msg)
	{
		Debug.Log("Space2D_Core. " + msg);
	}

	[SerializeField]
	private float m_minZoom = 1;
	[SerializeField]
	private float m_curZoom = 1.1f;
	[SerializeField]
	private float m_zoomStepScale = 1f;

	private PhysicalObject m_cur = null;
	private Dictionary<PhysicalObject, GameObject> m_renderers = new Dictionary<PhysicalObject, GameObject>();
	private Vector2d m_cameraOffset;
}
